/**
 *
 */

package com.yuan.unit;

import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.ParseException;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.CharArrayBuffer;
import org.apache.http.util.EntityUtils;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.text.TextUtils;
import android.util.DisplayMetrics;

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.StringWriter;
import java.security.SecureRandom;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;

/**
 * 打Log的工具类。
 * 
 * @author Jiongxuan Zhang
 */
public class Utils {

    /**
     * 打印正常的Debug信息
     * 
     * @param cls
     * @param log
     */
    public static void debug(Class<?> cls, String log) {
        debug(cls.getSimpleName(), log);
    }

    /**
     * 打印正常的Debug信息，其后参数类似于String.format
     * 
     * @param cls
     * @param log
     * @param objs
     */
    public static void debug(Class<?> cls, String log, Object... objs) {
        debug(cls.getSimpleName(), String.format(log, objs));
    }

    /**
     * 打印正常的Debug信息，其后参数类似于String.format
     * 
     * @param cls
     * @param log
     * @param objs
     */
    public static void debug(String tag, String log, Object... objs) {
        debug(tag, String.format(log, objs));
    }

    /**
     * 打印错误信息
     * 
     * @param cls
     * @param log
     */
    public static void error(Class<?> cls, String log) {
        error(cls.getSimpleName(), log);
    }

    /**
     * 打印错误信息，其后参数类似于String.format
     * 
     * @param cls
     * @param log
     * @param objs
     */
    public static void error(Class<?> cls, String log, Object... objs) {
        error(cls.getSimpleName(), String.format(log, objs));
    }

    /**
     * 打印错误信息
     * 
     * @param cls
     * @param log
     */
    public static void error(String tag, String log) {
        if (SystemInfo.DEBUG) {
            BLog.e(tag, log);
        }
    }

    /**
     * 打印错误信息，其后参数类似于String.format
     * 
     * @param cls
     * @param log
     * @param objs
     */
    public static void error(String tag, String log, Object... objs) {
        error(tag, String.format(log, objs));
    }

    /**
     * 打印错误信息
     * 
     * @param cls
     * @param log
     */
    public static void warning(Class<?> cls, String log) {
        warning(cls.getSimpleName(), log);
    }

    /**
     * 打印错误信息，其后参数类似于String.format
     * 
     * @param cls
     * @param log
     * @param objs
     */
    public static void warning(Class<?> cls, String log, Object... objs) {
        warning(cls.getSimpleName(), String.format(log, objs));
    }

    /**
     * 打印错误信息
     * 
     * @param cls
     * @param log
     */
    public static void warning(String tag, String log) {
        if (SystemInfo.DEBUG) {
            BLog.w(tag, log);
        }
    }

    /**
     * 打印错误信息，其后参数类似于String.format
     * 
     * @param cls
     * @param log
     * @param objs
     */
    public static void warning(String tag, String log, Object... objs) {
        warning(tag, String.format(log, objs));
    }

    /**
     * 获取堆栈信息
     * 
     * @param t
     * @return
     */
    public static String getStackTrace(Throwable t) {
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw, true);
        t.printStackTrace(pw);
        pw.flush();
        sw.flush();
        return sw.toString();
    }

    /**
     * 检查JSON的可用性
     * 
     * @param strJsonText
     * @return
     */
    public static boolean checkJsonValidation(String strJsonText) {
        return !TextUtils.isEmpty(strJsonText) && strJsonText.startsWith("{\"response\"");
    }

    public static boolean copyFile(String src, String des) {
        try {
            if (new File(src).exists()) {
                InputStream is = new FileInputStream(src);
                OutputStream os = new FileOutputStream(des, false);
                byte[] b = new byte[4098];
                int length;
                while ((length = is.read(b)) > 0) {
                    os.write(b, 0, length);
                }
                is.close();
                os.close();

                return true;
            }
        } catch (Exception e) {
            Utils.error(Utils.class, Utils.getStackTrace(e));
        }

        return false;
    }

    public static int getScreenWidth(Context context) {
        Resources res = context.getResources();
        DisplayMetrics ds = res.getDisplayMetrics();
        if (res.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
            return ds.widthPixels;
        } else {
            return ds.heightPixels;
        }
    }

    /**
     * 将entity转换成String
     */
    public static String httpEntityToString(final HttpEntity entity)
            throws IOException, ParseException {
        return httpEntityToString(entity, null);
    }

    /**
     * 将entity转换成String
     */
    public static String httpEntityToString(
            final HttpEntity entity, final String defaultCharset) throws IOException,
            ParseException {
        if (entity == null) {
            throw new IllegalArgumentException("HTTP entity may not be null");
        }
        InputStream instream = entity.getContent();
        if (instream == null) {
            return "";
        }
        if (entity.getContentLength() > Integer.MAX_VALUE) {
            throw new IllegalArgumentException("HTTP entity too large to be buffered in memory");
        }
        int i = (int) entity.getContentLength();
        if (i < 0) {
            i = 4096;
        }
        String charset = EntityUtils.getContentCharSet(entity);
        if (charset == null) {
            charset = defaultCharset;
        }
        if (charset == null) {
            charset = HTTP.DEFAULT_CONTENT_CHARSET;
        }

        // 看看是不是需要解压缩
        Header header = entity.getContentEncoding();
        if (header != null) {
            String value = header.getValue();
            if (TextUtils.isEmpty(value) == false && value.contains("gzip")) {
                instream = new GZIPInputStream(instream);
            }
        }
        Reader reader = new InputStreamReader(instream, charset);
        CharArrayBuffer buffer = new CharArrayBuffer(i);
        try {
            char[] tmp = new char[1024];
            int l;
            while ((l = reader.read(tmp)) != -1) {
                buffer.append(tmp, 0, l);
            }
        } finally {
            reader.close();
        }
        return buffer.toString();
    }

    private static final byte[] DES_KEY = ("com.qihoo.browser" + StringUtils
            .MD5Encode("com.qihoo.browser")).getBytes();

    @SuppressLint("TrulyRandom")
    public static byte[] des_encrypt(byte[] src) {
        if (src == null || src.length <= 0) {
            return null;
        }

        try {
            SecureRandom sr = new SecureRandom();
            DESKeySpec dks = new DESKeySpec(DES_KEY);
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
            SecretKey securekey = keyFactory.generateSecret(dks);
            Cipher cipher = Cipher.getInstance("DES");
            cipher.init(Cipher.ENCRYPT_MODE, securekey, sr);
            return cipher.doFinal(src);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static byte[] des_decrypt(byte[] src) {
        try {
            SecureRandom sr = new SecureRandom();
            DESKeySpec dks = new DESKeySpec(DES_KEY);
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
            SecretKey securekey = keyFactory.generateSecret(dks);
            Cipher cipher = Cipher.getInstance("DES");
            cipher.init(Cipher.DECRYPT_MODE, securekey, sr);
            return cipher.doFinal(src);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static byte[] desEncryptUsingCBC(byte[] src, byte[] key) {
        if (src == null || src.length <= 0) {
            return null;
        }

        try {
            IvParameterSpec zeroIv = new IvParameterSpec(key);
            DESKeySpec dks = new DESKeySpec(key);
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
            SecretKey securekey = keyFactory.generateSecret(dks);
            Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, securekey, zeroIv);
            return cipher.doFinal(src);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static byte[] desDecryptUsingCBC(byte[] src, byte[] key) {
        try {
            IvParameterSpec zeroIv = new IvParameterSpec(key);
            DESKeySpec dks = new DESKeySpec(key);
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
            SecretKey securekey = keyFactory.generateSecret(dks);
            Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, securekey, zeroIv);
            return cipher.doFinal(src);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static byte[] applyGZip(byte[] data) {
        if (data == null || data.length <= 0) {
            return null;
        }

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        GZIPOutputStream zipOutputSteam = null;
        InputStream inputStream = null;
        try {
            zipOutputSteam = new GZIPOutputStream(baos);
            inputStream = new BufferedInputStream(new ByteArrayInputStream(data));
            int len;
            byte[] buffer = new byte[4096];

            while ((len = inputStream.read(buffer)) != -1)
            {
                zipOutputSteam.write(buffer, 0, len);
            }
        } catch (Exception ex) {
            ex.printStackTrace();
            return null;
        } finally {
            try {
                if (inputStream != null) {
                    inputStream.close();
                }
                if (zipOutputSteam != null) {
                    zipOutputSteam.close();
                }
                baos.close();
            } catch (Exception ex) {
            }
        }
        return baos.toByteArray();
    }

    public static boolean isDeviceRooted() {
        File f = null;
        final String kSuSearchPaths[] = {
                "/system/bin/", "/system/xbin/", "/system/sbin/", "/sbin/", "/vendor/bin/"
        };
        try {
            for (int i = 0; i < kSuSearchPaths.length; i++)
            {
                f = new File(kSuSearchPaths[i] + "su");
                if (f != null && f.exists())
                {
                    return true;
                }
            }
        } catch (Exception e) {
        }
        return false;
    }

    public static void copyStream(InputStream in, OutputStream out) throws IOException {
        byte[] buffer = new byte[4096];
        int length = 0;
        while ((length = in.read(buffer)) > 0) {
            out.write(buffer, 0, length);
        }
        out.flush();
        in.close();
        out.close();
    }

}
